#ifndef __TYPE_H__
#define __TYPE_H__

#include <stdint.h>
#include "ast.h"

#ifdef __cplusplus
extern "C" {
#endif
/*------------------- C ----------------------*/

#define CHAR_SIZE         1
#define SHORT_SIZE        2
#define INT_SIZE          4
#define LONG_SIZE         4
#define LONG_LONG_SIZE    4
#define FLOAT_SIZE        4
#define DOUBLE_SIZE       8
#define LONG_DOUBLE_SIZE  8

/**
	... type category
	... CHAR / UCHAR ... from the view of C language
	... while I1/U1 ..  from the view of machine
	(1)
		Because ENUM could be seen as a INT, so it is put before FLOAT.
	(2)
		POINTER is considered as a scalar, not vector-type as struct.
*/
enum
{
	CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, ENUM,
	FLOAT, DOUBLE, LONGDOUBLE, POINTER, VOID, UNION, STRUCT, ARRAY, FUNCTION
};
/* type qualifier */
enum { CONST = 0x1, VOLATILE = 0x2 };
/*
 I1 : signed int8	1byte=8bit;  U1: unsigned int8
 V: no type              B: memory block, 
 see TypeCode()
*/
enum {I1, U1, I2, U2, I4, U4, F4, F8, V, B};

typedef struct type_t type_t;
	
typedef struct type_t
{
    int categ : 8; 
    int qual  : 8; 
    int align : 16;
    int size;
    struct type_t *bty;
} type_t;

extern type_t g_basic_types[VOID - CHAR + 1];
extern type_t g_string_type;

#define T(categ) (g_basic_types + categ)

void init_basic_types();

/*------------------- C ----------------------*/
#ifdef __cplusplus
}
#endif

#ifdef __cplusplus
/*------------------ C++ ---------------------*/

// struct function_t;
// struct param_t;
// struct ptype_t;
// struct stmt_t;

// struct field_t
// {
// 	char* name;
// 	char* id;
// 	type_t* type;
// };

// struct param_t
// {
// 	char* name;
// 	char* id;
// 	type_t* type;
// };

// struct sig_t
// {
// 	type_t** param;
// 	type_t** ret;
// };

// struct function_t
// {
// 	char* name;
// 	char* id;
// 	sig_t* sig;
// 	param_t* params;
// 	stmt_t** statements;
// };

// struct ptype_t
// {
// 	char* name;
// 	char* id;
//     ptype_t **field;
// 	function_t** func;
// };
/*------------------ C++ ---------------------*/

/**
	describes the parameter information in 
	function declaration or definition.
	id:	parameter name ,can be NULL.
	ty:	parameter type
	reg:	qualified by register or not
 */
struct parameter_t
{
	char *id; 
	type_t* ty; 
	int  reg; 
};

/**
	 The meaning of hasProto: 	see K&R	 A.10.1
	 (1)	
	 new-style definition:
	 	int max(int a,int b,int c){
	 	}
	 old-style definiition:
	 	
	 	see K&R A.8.6.3 	
	 	In the old-style declarator, the identifier list must be absent unless
	 	the declarator is used in the head of a function defition.
	 	No information about the types of the parameters is supplied by the declaration
	 	T D1(id-list);
	 	
	 	int max(a,b,c)	... This is a special old-style function declaration, because it appears in definition.
	 	int a,b,c;
	 	{
	 		
	 	}
	 new-style function declaration:
	 	int max(int a, int b, int c);
	 old-style function declation:
	 	int max();	... none of parameters type are specified.
	 (2)
	 	no proto:  we only know function returns int. It could be used as max(2,3), max(2,3,4)  in fact.
	 	has proto:	max(2,3,4) is right, max(2,3) wrong.
	 (3) hasProto:	has function prototype or not.
	 	hasEllipse:	has variable argument or not
	 	params:		parameter set
 */
struct signature_t
{
	int hasProto   : 16; 
	int hasEllipsis : 16;  
	parameter_t* params;
};

#endif


#endif  // __TYPE_H__
